#include <stdio.h>
#include <stdlib.h>
#include <math.h> 
#include <time.h>

/*Что делает искусственный нейрон? Простыми словами, он считает взвешенную сумму (сумма произведений числа на его вес) на своих входах, 
добавляет смещение (bias) 
Y = Σ (weight * input) + bias
и решает, следует это значение исключать или использовать дальше*/

#define _weight  3 // количество весов нейронки
double w[_weight];

/*Функция активации определяет выходное значение нейрона в зависимости от результата взвешенной суммы входов и порогового значения.*/

double activation(double a){ // функция активации (ступенька)
    return (a<=0) ? 0 : 1; //Функция А = активирована, если Y > граница, иначе нет
    //Функция принимает значение 1 (активирована), когда Y > 0 (граница), и значение 0 (не активирована) в противном случае.
}

double R(double inputs[3]){ // функция прямого распространения (result = значение1*вес1+значение2*вес2+значение3*вес3)
    double result = 0;
    for (unsigned i=0; i<10; i++)
        result += w[i]*inputs[i];
    return result;
}

void train(double data[4][3], double exp[4]){ // тренировка весов
    const double LR = 0.1; //(learning rate) скорость обучения 
    const unsigned Epoch = 50;// количество эпох т.е то количесвто раз сколько раз сеть будет пробегать по обучающей выборке    
    unsigned d, i, n;
    double error; // цена ошибки
    for (i=0; i<Epoch; i++){ // эпохи обучения
    /* Формула для "тренировки слоя: w(новый) = w(текущий) + (LR*(R(ожидаемый)-R(рассчитаный))*вход */
        for (d=0; d<4; d++){
            error = exp[d]-activation(R(data[d])); // преобразование целочисленного массива data в double
            for(n=0; n<_weight; n++){
                w[n]+=LR*error*data[d][n];
            }
        }
    }
}
int main(){
    double train_data[4][3] = {
                           {0.0,0.0,1.0},
                           {0.0,1.0,1.0},
                           {1.0,0.0,1.0},
                           {0.0,1.0,0.0}}; // тренировочные данные
    double expresult[4] = {0.0,0.0,1.0,0.0}; // массив ожидаемых результатов

    srand(time(NULL)); // опорное число для генератора случайных чисел
    for (unsigned i=0; i<3; i++){ // инициализация весов в цикле
        w[i] = rand()%10*0.1;
        printf("%f ", w[i]);
    }
    printf("\n");

    train(train_data, expresult); // тренировка весов в функции

    for(unsigned i=0; i<3; i++){
        w[i]=(w[i]>0) ? w[i] : 0; // проверяем веса если больше 0, то сам вес иначе 0 чтобы не было отрицательных результатов
        printf("%f ", w[i]);
    }
    printf("\n");

    double new[3]={0.0,1.0,0.0}; // новая ситуация
    printf("%f", activation(R(new)));


    return 0;
}